﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Krile.Kernel.Data;
using System.Xml.Serialization;
namespace Krile.Data
{
    public class TabData : IDisposable
    {
        [XmlIgnore()]
        private Forms.MainForm.Controls.XTab.XTabTLItem parentTabItem;

        [XmlIgnore()]
        public Forms.MainForm.Controls.XTab.XTabTLItem Parent
        {
            get { return parentTabItem; }
            set
            {
                parentTabItem = value;
                if (parentTabItem != null && nameBuffer != null)
                {
                    parentTabItem.Name = nameBuffer;
                    nameBuffer = null;
                }
            }
        }

        public TabData()
        {
            this.Locked = false;
            parentTabItem = null;
        }

        public TabData(Forms.MainForm.Controls.XTab.XTabTLItem parent)
        {
            this.Locked = false;
            parentTabItem = parent;
        }

        void parentTabItem_OnClosed()
        {
            this.Dispose();
        }

        Cores.StatusManager.XStatusRegisteredCallback registered = null;
        Cores.StatusManager.XStatusRegisteredCallback removed = null;
        Cores.StatusManager.XStatusRegisteredCallback updated = null;
        Action sortUpdated = null;
        object csLocker = new object();
        List<XStatus> containStatus = null;

        public event EventHandler ContainStatusChanged;

        internal IEnumerable<XStatus> ContainStatuses
        {
            get
            {
                lock (csLocker)
                {
                    return containStatus.ToArray();
                }
            }
        }

        private bool initialized = false;
        public void InitTabData()
        {
            if (initialized)
                Dispose();
            registered = new Cores.StatusManager.XStatusRegisteredCallback(StatusManager_RegistStatus);
            removed = new Cores.StatusManager.XStatusRegisteredCallback(StatusManager_RemoveStatus);
            updated = new Krile.Cores.StatusManager.XStatusRegisteredCallback(StatusManager_UpdateStatus);
            containStatus = new List<XStatus>();
            Core.StatusManager.OnXStatusRegistered += registered;
            Core.StatusManager.OnXStatusRemoved += removed;
            Core.StatusManager.OnXStatusUpdated += updated;
            containStatus.AddRange(Core.StatusManager.ExtractXStatuses(ContainSearchData));
            SortStatus();
            sortUpdated = new Action(StatusServerSorts_StatusSortComparisonUpdated);
            Cores.StatusManager.StatusSorter.StatusSortComparisonUpdated += sortUpdated;
            var ids = from s in Core.PluginManager.GetServiceEnumerator().ToArray<Service>()
                      select s.Id;
            LinkedServiceIds = ids.ToArray<string>();
            initialized = true;
            System.Diagnostics.Debug.WriteLine("Initialized tab:" + this.Name);
        }

        void StatusServerSorts_StatusSortComparisonUpdated()
        {
            SortStatus();
        }

        private void SortStatus()
        {
            for(int i = 0; i < 100; i++)
            {
                try
                {
                    containStatus.Sort(new Comparison<XStatus>(Cores.StatusManager.StatusSorter.StatusSortComparison));
                    return;
                }
                catch (ArgumentException) { }
                catch (InvalidOperationException ioe)
                {
                    if (ioe.InnerException is NullReferenceException)
                    {
                        // Null reference
                        throw ioe.InnerException;
                    }
                }
                System.Threading.Thread.Sleep(10);
            }
            throw new KrileManagementException("Status sorting failed!");
        }

        public void Dispose()
        {
            if (initialized)
            {
                Core.StatusManager.OnXStatusRegistered -= registered;
                Core.StatusManager.OnXStatusRemoved -= removed;
                Core.StatusManager.OnXStatusUpdated -= updated;
                Cores.StatusManager.StatusSorter.StatusSortComparisonUpdated -= sortUpdated;
                registered = null;
                removed = null;
                sortUpdated = null;
                lock (csLocker)
                {
                    containStatus = null;
                }
                initialized = false;
                System.Diagnostics.Debug.WriteLine("Disposed tab:" + this.Name);
            }
        }

        void StatusManager_RegistStatus(IEnumerable<XStatus> xstatuses)
        {
            if (xstatuses == null)
                return;
            var newst = from s in xstatuses
                        where ContainSearchData == null || ContainSearchData.IsMatched(s.BaseStatus)
                        select s;
            if (newst != null && newst.Count() != 0)
            {
                lock (csLocker)
                {
                    containStatus.AddRange(newst);
                }
                SortStatus();
                if (ContainStatusChanged != null)
                    ContainStatusChanged.Invoke(this, new EventArgs());
                var newx = from s in newst
                           where s.Unread
                           select s;
                if (newx.Count() > 0)
                {
                    if (!this.UnNotify)
                    {
                        System.Diagnostics.Debug.WriteLine("Notify tab:" + this.Name);
                        RecvNew = true;
                        if (Core.NotificationManager != null)
                            Core.NotificationManager.SetNotificate(newx, NotifySound);
                    }
                }
            }
        }

        void StatusManager_RemoveStatus(IEnumerable<XStatus> xstatuses)
        {
            bool adf = false;
            lock (csLocker)
            {
                foreach (var xs in xstatuses)
                {
                    if (containStatus.Contains(xs))
                    {
                        containStatus.Remove(xs);
                        adf = true;
                        break;
                    }
                }
            }
            if (adf && ContainStatusChanged != null)
                ContainStatusChanged.Invoke(this, new EventArgs());
        }

        void StatusManager_UpdateStatus(IEnumerable<XStatus> xstatuses)
        {
            if (xstatuses == null)
                return;
            List<XStatus> newx = new List<XStatus>();
            bool upd = false;
            lock (csLocker)
            {
                foreach (var xs in xstatuses)
                {
                    if (containStatus.Contains(xs))
                    {
                        if (ContainSearchData != null && !ContainSearchData.IsMatched(xs.BaseStatus))
                        {
                            containStatus.Remove(xs);
                            upd = true;
                        }
                    }
                    else
                    {
                        if (ContainSearchData == null || ContainSearchData.IsMatched(xs.BaseStatus))
                        {
                            containStatus.Add(xs);
                            upd = true;
                        }
                    }
                }
            }
            if (upd)
            {
                SortStatus();
                if (ContainStatusChanged != null)
                    ContainStatusChanged.Invoke(this, new EventArgs());
            }
            if (newx.Count > 0)
            {
                if (!this.UnNotify)
                {
                    RecvNew = true;
                }
            }
        }

        private string nameBuffer = null;
        /// <summary>
        /// Tab name (equals Parent.Name)
        /// </summary>
        public string Name
        {
            get
            {
                if (parentTabItem == null)
                    return nameBuffer;
                else
                    return parentTabItem.Name;
            }
            set
            {
                if (parentTabItem == null)
                    nameBuffer = value;
                else
                    parentTabItem.Name = value;
            }
        }

        private bool unNotify = false;
        /// <summary>
        /// Unnotify state
        /// </summary>
        public bool UnNotify
        {
            get { return unNotify; }
            set
            {
                unNotify = value;
                if (parentTabItem != null)
                    parentTabItem.UpdateIcon();
            }
        }

        private bool locked = false;
        /// <summary>
        /// Locking state in this tab
        /// </summary>
        public bool Locked
        {
            get { return locked; }
            set
            {
                locked = value;
                if (parentTabItem != null)
                    parentTabItem.UpdateIcon();
            }
        }

        /// <summary>
        /// Notification sound
        /// </summary>
        public string NotifySound { get; set; }

        private bool recvNew = false;
        /// <summary>
        /// Receive new state
        /// </summary>
        public bool RecvNew
        {
            get { return recvNew; }
            set
            {
                if (parentTabItem != null && parentTabItem.Selected)
                    recvNew = false;
                else
                    recvNew = value;
                if (parentTabItem != null)
                    parentTabItem.UpdateIcon();
            }
        }

        /// <summary>
        /// Search data cluster which be contained this tab.
        /// </summary>
        public SearchDataCluster ContainSearchData { get; set; }

        /// <summary>
        /// Linked Service id
        /// </summary>
        public String[] LinkedServiceIds { get; set; }

        /// <summary>
        /// Selected status UID
        /// </summary>
        [XmlIgnore()]
        public ulong SelectedStatus { get; set; }

        /// <summary>
        /// Scrolling offset
        /// </summary>
        [XmlIgnore()]
        public long ScrollOffset { get; set; }

    }
}
